package org.qy.mybatisplus.client.config.datasource;

import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;

/**
 * @Description:	数据源
 * @Author:		方宇康
 * @CreateDate:	2019/1/7
 * @Version:      	1.0.0.1
 * @Company:       联通智网科技有限公司
 */
@SuppressWarnings("all")
@Slf4j
@Configuration
@MapperScan(basePackages = {"org.qy.mybatisplus.client"}, sqlSessionTemplateRef = "mysqlSqlSessionTemplate")
@EnableConfigurationProperties(HikariProperties.class)
@ConditionalOnClass(HikariProperties.class)
@AutoConfigureBefore(DataSourceAutoConfiguration.class)
public class DataSourceConfig
{
    @Autowired
    private HikariProperties properties;

    @Value("${mybatis-plus.mapperLocations}")
    private String mapperLocations;

    @Autowired
    PaginationInterceptor paginationInterceptor;

    @RefreshScope
    @Bean(name = "mysqlDataSource", destroyMethod = "close")
    @Primary
    public DataSource mysqlDataSource()
    {
        log.info("MySqlDataSourceConfig|mysqlDataSource() >>> {}", properties);
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setJdbcUrl(properties.getJdbcUrl());
        hikariConfig.setUsername(properties.getUsername());
        hikariConfig.setPassword(properties.getPassword());
        hikariConfig.setDriverClassName(properties.getDriverClassName());
        hikariConfig.addDataSourceProperty("dataSource.cachePrepStmts", properties.getCachePrepStmts());
        hikariConfig.addDataSourceProperty("dataSource.prepStmtCacheSize", properties.getPrepStmtCacheSize());
        hikariConfig.addDataSourceProperty("dataSource.prepStmtCacheSqlLimit", properties.getPrepStmtCacheSqlLimit());
        hikariConfig.addDataSourceProperty("dataSource.useServerPrepStmts", "true");
        hikariConfig.addDataSourceProperty("useLocalSessionState", properties.getUseLocalSessionState());
        hikariConfig.addDataSourceProperty("useLocalTransactionState", properties.getUseLocalTransactionState());
        hikariConfig.addDataSourceProperty("rewriteBatchedStatements", properties.getRewriteBatchedStatements());
        hikariConfig.addDataSourceProperty("cacheResultSetMetadata", properties.getCacheResultSetMetadata());
        hikariConfig.addDataSourceProperty("cacheServerConfiguration", properties.getCacheServerConfiguration());
        hikariConfig.addDataSourceProperty("elideSetAutoCommits", properties.getElideSetAutoCommits());
        hikariConfig.addDataSourceProperty("maintainTimeStats", properties.getMaintainTimeStats());
        hikariConfig.addDataSourceProperty("logAbandoned", properties.getLogAbandoned());
        hikariConfig.addDataSourceProperty("removeAbandonedTimeout", properties.getRemoveAbandonedTimeout());
        hikariConfig.setConnectionTestQuery(properties.getConnectionTestQuery());
        hikariConfig.setPoolName(properties.getPoolName());
        hikariConfig.setMaximumPoolSize(properties.getMaxActive());
        hikariConfig.setMaxLifetime(properties.getMaxLifetime());
        hikariConfig.setIdleTimeout(properties.getIdleTimeout());
        hikariConfig.setConnectionTimeout(properties.getConnectionTimeout());
        hikariConfig.setReadOnly(properties.getReadOnly());
        return new HikariDataSource(hikariConfig);
    }
    
    /**
	 * 分页插件
	 */
	@Bean
	public PaginationInterceptor paginationInterceptor()
    {
        log.info("MySqlDataSourceConfig|paginationInterceptor() >>> ");
		return new PaginationInterceptor();
	}

    @Bean(name = "mysqlSqlSessionFactory")
    @Primary
    public SqlSessionFactory mysqlSqlSessionFactory(@Qualifier("mysqlDataSource") DataSource dataSource) throws Exception
    {
        log.info("MySqlDataSourceConfig|mysqlSqlSessionFactory() >>> ");
        MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
        mybatisSqlSessionFactoryBean.setDataSource(dataSource);
	    MybatisConfiguration configuration = new MybatisConfiguration();
        mybatisSqlSessionFactoryBean.setConfiguration(configuration);
        mybatisSqlSessionFactoryBean.setPlugins(new Interceptor[]{paginationInterceptor, new PerformanceInterceptor()});
        mybatisSqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));
        return mybatisSqlSessionFactoryBean.getObject();
    }

    @Bean(name = "mysqlTransactionManager")
    @Primary
    public DataSourceTransactionManager mysqlTransactionManager(@Qualifier("mysqlDataSource") DataSource dataSource)
    {
        log.info("MySqlDataSourceConfig|mysqlTransactionManager() >>> ");
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean(name = "mysqlSqlSessionTemplate")
    @Primary
    public SqlSessionTemplate mysqlSqlSessionTemplate(@Qualifier("mysqlSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception
    {
        log.info("MySqlDataSourceConfig|mysqlSqlSessionTemplate() >>> ");
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}
